import os
import threading
import Queue
from threading import Lock

from ivic.core import Logging
from ivic.vspace.VSpace import *
from ivic.vspace.ServerMonitor import *
from ivic.vspace.Config import  *

logger = Logging.get_logger('ivic.vspace.Server')

#****************vspace server class************************#
class VSpaceServer:
    
    def __init__(self, config):
        # save config
        self.config = config
 
        # dump config string
        for k, v in self.config.items():
            if type(v) == str:
                logger.debug('config var: %s = %s', k, v)
        
        # save a VSpace info when it was created
        self.userspace = []
        self.synclock = Lock()
        self.servermon = None

    def createVSpace(self, user, resolution='1024x768'):
        try:
            logger.debug("Create vSpace Instance!")
            vspace = create(user, resolution)
            logger.debug("Run vSpace Instance")
            if vspace != None : vspace.run()
            self.synclock.acquire()
            self.userspace.append(vspace)
            self.synclock.release()
            logger.debug("Finishe Create vSpace Instance")
            retspace = []
            retspace.append(vspace.dict())
            return retspace
        except Exception, e:
            self.synclock.release()
            logger.error('createvspace:%s' % e)
            return []
        

    def deleteVSpace(self, vnc_address):
        logger.debug("Try to terminate vSpace %s" % vnc_address)
        try:        
            vspaces = [vspace for vspace in self.userspace\
                            if vnc_address == vspace.vnc_address]
            
            if vspaces:
                for each in vspaces:
                    try:
                        logger.debug("Terminate vSpace %s" % each.vnc_address)
                        each.kill()
                    except Exception, e:
                        logger.error('Kill VSpace:%s' % e)
                    #we need another way to handle this issue.
                    #vspace instance need to poll themselves to update the state
#                    self.synclock.acquire()
#                    self.userspace.remove(each)
#                    self.synclock.release()
        except Exception, e:
            logger.error('terminateSpace:%s' % e)
            return []
        
    def getVSpaceList(self):
        try:
            vspaces = [vspace.dict() for vspace in self.userspace]
            return vspaces
        except Exception, e:
            logger.error('queryAllSpace:%s' % e)
            return []   

    def migrateVSpace(self):
        pass
    
    def queryVSpace(self, user):
        try:
            vspaces = [vspace.dict() for vspace in self.userspace\
                        if user == vspace.user]
            return vspaces                
        except Exception, e:
            return []
        
    def queryAllVSpaceString(self):
        try:
            vspaces = self.getVSpaceList()
            if len(vspaces) >= 1:
                return map(str, vspaces)
        except Exception, e:
            logger.error('queryAllSpaceString:%s' % e)
            return []
        
    def setServerMonitor(self,mon):
        self.servermon = mon
        
    def poll(self):
        try:
            self.servermon.report()
        except Exception,e:
            logger.error('poll vspace soap server state:%s' % e)
        return ""

#****************vspaceserver main tracker ********************#
class VSpaceTracker(threading.Thread):
    
    def __init__(self, server):
        threading.Thread.__init__(self)
        self.userspace = server.userspace
        self.running = True
        self.setName("Thread VSpace Tracker")
        
    def run(self):
        try:
            while self.running:
                try:
                    for space in self.userspace:
                        try:
                            if space.state == "running": 
                                space.poll()
                        except Exception, e:
                            logger.error("Try to dect thread %s" % e)       
                except Exception, e:
                    logger.error("Running Tracker Error: %s" % e)
                time.sleep(5)
        except Exception, e:
            logger.error("Running Tracker Error: %s" % e)
                
    def stop(self):
        self.running = False 
        
#****************vspaceserver main reporter ********************#
attr_map = { "uuid":"uuid",
            "state":"state",
            "resolution":"resolution",
            "address":"vnc_address",
            "create_time":"create_time",
            "end_time":"end_time",
            "user_id":"user"}

class VSpaceReporter(threading.Thread):
    
    host_ip_addr = None
    
    def __init__(self, report_url=None):
        threading.Thread.__init__(self)
        
        self.url = report_url
        
        self.queue = Queue.Queue(0)
        
        self.server_uuid = get_vm_uuid()            
        if self.server_uuid == None:
            self.running = False
        else:
            self.running = True
        
    def putEvent(self, eventType, info):
        try:
            self.queue.put((eventType, info))
        except Exception, e:
            logger.error("putEvent: %s" % e) 
            
    def serialize(self, info):
        try:
            message = ""
            if type(info) == dict:
                for key, value in attr_map.items():
                         if info.has_key(value) and (len(info[value]) > 1):
                             message = message + "VSpace[%s]=%s&" % (key, info[value])
                
                if VSpaceReporter.host_ip_addr is None:             
                    address = None
                    try:
                        address = Utils.external_address()
                    except Exception, e:
                        pass
                    if address is None: address = get_ip_address('eth0')
                    VSpaceReporter.host_ip_addr = address
                     
                message += "VSpace[server_addr]=" + VSpaceReporter.host_ip_addr
                #add vspace-server uuid
                message += '&VSpace[vmiuuid]=%s' % self.server_uuid
                #legacy code
                message += '&server=%s' % self.server_uuid
            return message
        except Exception, e:
            logger.error("Serialize: %s" % e)
            return ""
        
    def run(self):
        try:
            while self.running:
                try:
                    eventType, info = self.queue.get()
                    
                    message = self.serialize(info)
                    if message == "": continue
                    
                    url = self.url
                    command = ""
                    try:
                        if eventType == "START":
                            command = "curl -X POST -d \"%s\" -H \"Accept: text/xml\" %s" % (message, url)
                        elif eventType in ("STOP","RUNNING"):
                            command = "curl -X PUT -d \"%s\" -H \"Accept: text/xml\" %s " % (message, url + info["uuid"])
                        elif evenType == "KILL":
                            command = "curl -X DELETE -H \"Accept: text/xml\" %s" % url + info["uuid"]
                        
                        if len(command) > 0:
                            try:
                                os.system(command)
                            except Exception, e:
                                logger.error("%s" % e)
                        logger.debug(command)            
                    except Exception, e:
                        logger.error("%s" % e)
                        
                    
                except Exception, e:
                    logger.error("Reporter: %s" % e)
        except Exception, e:
            self.running = False
            logger.error("Report: %s" % e)
                
    def stop(self):
        self.running = False 
        
class Singleton(object):
    
    reporter = None
    lock = Lock()
    
    @staticmethod
    def Reporter(report_url=None):
        if Singleton.reporter is None:
            Singleton.lock.acquire()
            if Singleton.reporter is None:
                Singleton.reporter = VSpaceReporter(report_url)
            Singleton.lock.release()
        return Singleton.reporter 
